// Ludo.cpp : Defines the entry point for the console application.
//


#include <Inventor\Win\SoWin.h>
#include <Inventor\Win\viewers\SoWinExaminerViewer.h>
#include <Inventor\nodes\SoCube.h>
#include <Inventor\nodes\SoSphere.h>
#include <Inventor\nodes\SoSeparator.h>
#include <Inventor\nodes\SoTranslation.h>
#include <Inventor\nodes\SoRotation.h>
#include <Inventor\nodes\SoCylinder.h>
#include <Inventor\nodes\SoTexture2.h>
#include <Inventor\nodes\SoBaseColor.h>
#include <Inventor\nodes\SoMatrixTransform.h>
#include <Inventor\nodes\SoSubNode.h>
#include <Inventor\nodes\DoFrameSeparator.h>
#include <Inventor\sensors\SoTimerSensor.h>

#include <Inventor\SoRef.hh>

#include <Do\Flow\Nodes\WhileFlowNode.h>
#include <Do\Flow\Nodes\ModfFlowNode.h>
#include <Do\Flow\Nodes\MessageDispatcher.h>
#include <Do\Flow\Nodes\BoolFlowNodes.h>

#include <tchar.h>

namespace Do {
  using namespace Do::Flow;
  using namespace Do::Flow::Nodes;
}

enum GameColorIds
{
  RED, 
  GREEN, 
  BLUE, 
  YELLOW
};




class TokenNode : public SoSeparator
{
private:
  SoRef<SoTranslation> position_;

public:

  TokenNode(SbVec3f const& pos, SoRefnc& shape) 
    : position_(mkref<SoTranslation>(pos)) 
  {
    position_->translation = pos;

    addChildren(position_, shape);
  }
};


class FortressNode : public SoSeparator
{
public:
  FortressNode(SbMatrix const& placement, SbColor const& color, SoRefnc& shape) {
    addChildren (
      mkref<SoMatrixTransform>(placement),
      mkref<SoBaseColor>(color),
      mkref<TokenNode>(SbVec3f( 1,  1, 0), shape),
      mkref<TokenNode>(SbVec3f( 1, -1, 0), shape),
      mkref<TokenNode>(SbVec3f(-1,  1, 0), shape),
      mkref<TokenNode>(SbVec3f(-1, -1, 0), shape)
    ); 
  }
};


class BoardNode : public SoSeparator
{
public:
  BoardNode() {
    addChildren(
      mkref<SoTexture2>("Ludo.png"),
      mkref<SoTranslation>(SbVec3f(0.0, 0.0, -0.15f)),
      mkref<SoCube>(16.0f, 16.0f, 0.3f, 0x01)
    );
  }
};



void timerCB(void* data, SoSensor* sensor)
  {
    Do::FrameSeparator* frame = reinterpret_cast<Do::FrameSeparator*>(data);
    frame->translation = frame->translation.getValue() + SbVec3f(0,0.1f,0);
    frame->dbgThis();
  }

int _tmain(int argc, _TCHAR* argv[])
{
  HWND toplevel = SoWin::init("Ludo");

  Do::FrameSeparator::initClass();

    SoWinExaminerViewer viewer(toplevel);

  SbColor color_red    (218.0f/256.0f,  37.0f/256.0f,  28.0f/256.0f);
  SbColor color_green  (133.0f/256.0f, 194.0f/256.0f,  38.0f/256.0f);
  SbColor color_blue   (  0.0f/256.0f, 147.0f/256.0f, 221.0f/256.0f);
  SbColor color_yellow (248.0f/256.0f, 195.0f/256.0f,   1.0f/256.0f);

  SbMatrix mat_red    (SbVec3f(-4.5f, -4.5f, 0.0f), SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(1.0f, 0.0f, 0.0f)));
  SbMatrix mat_green  (SbVec3f(-4.5f,  4.5f, 0.0f), SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(1.0f, 0.0f, 0.0f)));
  SbMatrix mat_blue   (SbVec3f( 4.5f, -4.5f, 0.0f), SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(1.0f, 0.0f, 0.0f)));
  SbMatrix mat_yellow (SbVec3f( 4.5f,  4.5f, 0.0f), SbRotation(SbVec3f(1.0f, 0.0f, 0.0f), SbVec3f(1.0f, 0.0f, 0.0f)));

  SoRef<SoSeparator> token_shape = mkref<SoSeparator>(
    mkref<SoRotation>(SbVec3f(0,1,0), SbVec3f(0,0,1)),
    mkref<SoCylinder>(0.4f, 0.333f)
    );

  SoRef<SoSeparator> root = mkref<SoSeparator>( 
    mkref<BoardNode>(), 
    mkref<FortressNode>(mat_red,    color_red,    token_shape),
    mkref<FortressNode>(mat_green,  color_green,  token_shape),
    mkref<FortressNode>(mat_blue,   color_blue,   token_shape),
    mkref<FortressNode>(mat_yellow, color_yellow, token_shape),
    mkref<SoCube>()
    );
  
  SoRef<Do::FrameSeparator> frame = mkref<Do::FrameSeparator>(mkref<SoCube>());

  viewer.setSceneGraph(root);
  viewer.show();
#if 0
  Do::Flow::ModfFlowNode modf;
  g_time.out.now >>= modf.in.dividend;
                     modf.in.divisor      <<= 1.0;
                     modf.in.maxQuotient  <<= 3.0;
//                   modf.out.quotient >>= [&] { handleCount(modf.out.quotient()); };
#endif
#if 0
  time.out.now >>= modf.in.dividend
                   modf.in.divisor   <<=  1.0
                   modf.in.max       <<=  3.0
                   modf.out.quotient
                   modf.out.fracPart  >>=                  >>= jump.in.t
                   modf.out.quotPart  >>=  track.in.offset
                                              track.in.base   <<= 0
                                              track.out.pos0  >>= jump.in.pos0
                                              track.out.pos1  >>= jump.in.pos0
                                                                  jump.out.pos >>= token.in.pos

#endif


  SoTimerSensor timer_sensor;
  timer_sensor.setInterval(SbTime(0.5));
  timer_sensor.setFunction(timerCB);
  timer_sensor.setData(frame.get());
  timer_sensor.schedule();

  Do::WhileFlowNode main_loop;
  Do::MessageDispatcher msg_dispatcher;
  Do::NegFlowNode neg_quit;

  main_loop.out.drive   >>= msg_dispatcher.in.drive;
                            msg_dispatcher.out.quit >>=  neg_quit.in;
                                                         neg_quit.out >>= main_loop.ctl.cond;

  main_loop.invoke();

//  SoWin::mainLoop();

	return 0;
}
